<?php
// +----------------------------------------------------------------------
// | B5Yii2CMF V3.0 [快捷通用基础管理开发平台]
// +----------------------------------------------------------------------
// | Author: 冰舞 <357145480@qq.com>
// +----------------------------------------------------------------------
declare (strict_types=1);

namespace api\modules\admin;

use api\utils\libs\BaseController;
use api\utils\libs\FilterLogin;
use common\extend\exception\ErrorCode;
use common\extend\exception\B5HttpException;
use common\models\system\Admin;
use common\services\PermissionService;
use yii\base\Action;

/**
 * 所有需要登录验证的基类
 * Class AuthController
 * @package api\modules\admin
 */
class AuthController extends BaseController
{
    protected int $user_id;
    protected ?array $token = null;
    protected ?Admin $user = null;

    public function behaviors(): array
    {
        return [
            //登录判断
            'FilterLogin' => [
                'class' => FilterLogin::class,
                'type' => 'admin'
            ]
        ];
    }

    /**
     * 方法前执行操作
     * @param $action
     * @return bool
     * @throws B5HttpException
     */
    public function beforeAction($action): bool
    {
        if (!parent::beforeAction($action)) {
            return false;
        }
        $this->token = $this->request->getBodyParam('__token__');
        $user_id = $this->token ? intval($this->token['user_id'] ?? 0) : 0;
        if ($user_id < 1) {
            throw new B5HttpException(400, '未登录或登录失效', ErrorCode::API_TOKEN_ERROR);
        }
        $this->user_id = $user_id;

        if (!$this->checkAuth($action)) {
            throw new B5HttpException(400, '无权限此操作', ErrorCode::API_NO_AUTH);
        }
        /**
         * 这里其实也可以进行用户信息获取、判断、设置$this->user
         * 但是考虑并不是每个接口都需要获取用户信息，较少数据库查询，所以写了getUser方法在需要的时候调用
         * 如果这个放置了getUser中的代码，则getUser可以直接返回$this->user，也不影响整体
         */

        return true;
    }

    /**
     * 获取登录用户信息
     * @return Admin
     * @throws B5HttpException
     */
    public function getUser(): Admin
    {
        if ($this->user) return $this->user;
        $user = Admin::findOne($this->user_id);
        if (!$user || $user->status != 1) {
            throw new B5HttpException(400, '账号不存在或已禁用', ErrorCode::API_TOKEN_ERROR);
        } else {
            $this->user = $user;
            return $user;
        }
    }

    /**
     * 检测权限
     * @param $action
     * @return bool
     */
    private function checkAuth(Action $action): bool
    {
        if (!$this->user_id) return false;

        // 获取分组名、控制器名、方法名
        $groupName = '';
        $controllerName = $action->controller->id;
        $actionName = $action->id;
        $controllerArray = explode('/', $controllerName);
        if (count($controllerArray) > 1) {
            $groupName = $controllerArray[0];
            $controllerName = $controllerArray[1];
        }
        return PermissionService::hasPerm($this->user_id, $groupName, $controllerName, $actionName);
    }
}